import 'package:flutter/material.dart';

class TabMenu extends StatefulWidget {
  static const BGCOLOR = Color(0xFFF7F9FB);
  static const SELECTCOLOR = Color(0xFF212121);
  static const NORMALCOLOR = Color(0xFF717171);
  static const INDICATORCOLOR = Color(0xFF2A81FF);

  final List<Widget> widgets;
  final List<String> titles;
  final List<Widget>? rightWidgets;
  final Widget? headWidget;
  final bool isScrollable;
  final double height;
  final double sliverHeight;
  final Color? backgroundColor;
  final Color? indicatorColor;
  final Color? selectColor;
  final Color? normalColor;
  final TextStyle? normalStyle;
  final TextStyle? selectStyle;
  final double? fontSize;
  final FontWeight? fontWeight;
  final FontWeight? selectFontWeight;
  final int initIndex;
  final ValueChanged<int>? onIndexChange;
  final double? leftPadding;
  final EdgeInsetsGeometry? labelPadding;
  final EdgeInsetsGeometry? indicatorPadding;
  final bool? pinned;
  final bool? isShowBottomLine;
  //tabBar view 滑动
  final ScrollPhysics? tabBarViewPhysics;
  //指示器 宽度默认26，为空则文字宽度，高度是indicatorBorderSide.width
  final double? indicatorWidth;
  final BorderSide indicatorBorderSide;
  final TabBarIndicatorSize? indicatorSize;

  const TabMenu(
      {Key? key,
        required this.titles,
        required this.widgets,
        this.rightWidgets,
        this.isScrollable = false,
        this.height = 35,
        this.backgroundColor = BGCOLOR,
        this.indicatorColor = INDICATORCOLOR,
        this.selectColor = SELECTCOLOR,
        this.normalColor = NORMALCOLOR,
        this.fontSize = 18,
        this.fontWeight = FontWeight.bold,
        this.selectFontWeight = FontWeight.normal,
        this.headWidget,
        this.onIndexChange,
        this.initIndex = 0,
        this.leftPadding = 0,
        this.labelPadding,
        this.pinned=false,
        this.isShowBottomLine,
        this.tabBarViewPhysics,
        this.sliverHeight = 100,
        this.normalStyle,
        this.selectStyle,
        this.indicatorWidth = 26,
        this.indicatorBorderSide = const BorderSide(width: 2.0, color: Color(0xff2A81FF)), this.indicatorSize = TabBarIndicatorSize.label, this.indicatorPadding,
      })
      : assert(titles.length > 0 &&
      widgets.length > 0 &&
      widgets.length == titles.length),
        super(key: key);

  @override
  TabMenuState createState() => TabMenuState();
}

class TabMenuState extends State<TabMenu> with TickerProviderStateMixin {
  late TabController tabController;

  @override
  void initState() {
    super.initState();
    tabController = TabController(
        length: widget.widgets.length,
        vsync: this,
        initialIndex: widget.initIndex);
    //监听tab切换
    tabController.addListener(() {
      widget.onIndexChange?.call(tabController.index);
    });
  }

  @override
  void didUpdateWidget(covariant TabMenu oldWidget) {
    super.didUpdateWidget(oldWidget);
    if(widget.widgets.length!=oldWidget.widgets.length){
      tabController = TabController(
          length: widget.widgets.length,
          vsync: this,
          initialIndex: widget.initIndex);
      //监听tab切换
      tabController.addListener(() {
        widget.onIndexChange?.call(tabController.index);
      });
    }
  }

  @override
  Widget build(BuildContext context) {

    if (widget.headWidget == null) {
      return Column(
        children: [buildTabBar(), Flexible(child: buildBodyView())],
      );
    }
    return NestedScrollView(
      headerSliverBuilder: (context, can) {
        return [
          SliverPersistentHeader(
            delegate: _SliverPersistentHeaderDelegate(
                widget: widget.headWidget!, height: widget.sliverHeight),
            pinned: widget.pinned??false,
          ),
          SliverPersistentHeader(
            delegate: SliverTabBarDelegate(
                widget: getBar(),
                color: widget.backgroundColor,
                height: widget.height,
                isShowBottomLine:widget.isShowBottomLine
            ),
            pinned: true,
          ),
        ];
      },
      body: buildBodyView(),
    );
  }

  buildBodyView() {
    //构造 TabBarView
    Widget tabBarBodyView = TabBarView(
      controller: tabController,
      physics: widget.tabBarViewPhysics,
      //创建Tab页
      children: widget.widgets,
    );
    return tabBarBodyView;
  }

  buildTabBar() {
    //构造 TabBar
    Widget tabBar = Container(
        width: double.infinity,
        height: widget.height,
        decoration: BoxDecoration(color: widget.backgroundColor),
        child: getTabbar());
    return tabBar;
  }

  Widget getTabbar() {
    if (widget.rightWidgets?.isNotEmpty == true) {
      return Row(
        children: [
          SizedBox(width: widget.leftPadding,),
          Expanded(child: getBar()),
          ...widget.rightWidgets!,
        ],
      );
    }
    return getBar();
  }

  TabBar getBar() {
    TabBar tabbar = TabBar(
        indicator: CustomUnderlineTabIndicator(indicatorWidth: widget.indicatorWidth,borderSide: widget.indicatorBorderSide),
        // padding: EdgeInsets.only(right: (widget.rightWidgets?.length ?? 0) * 50),
        isScrollable: widget.isScrollable,
        labelPadding: widget.labelPadding,
        //设置tab文字得类型
        labelStyle:
        TextStyle(fontSize: widget.fontSize, fontWeight: widget.selectFontWeight).merge(widget.selectStyle),
        unselectedLabelStyle: TextStyle(fontSize: widget.fontSize, fontWeight: widget.fontWeight).merge(widget.normalStyle),
        //设置tab选中得颜色
        labelColor: widget.selectColor,
        //设置tab未选中得颜色
        unselectedLabelColor: widget.normalColor,
        ///指示器大小计算方式，TabBarIndicatorSize.label跟文字等宽,TabBarIndicatorSize.tab跟每个tab等宽
        indicatorSize: widget.indicatorSize,
        ///指示器颜色
        indicatorColor: widget.indicatorColor,
        indicatorPadding: widget.indicatorPadding ?? const EdgeInsets.symmetric(horizontal: 12),
        //生成Tab菜单
        controller: tabController,
        //构造Tab集合
        tabs: widget.titles.map((e) => Tab(text: e)).toList()
    );
    return tabbar;
  }
}

//
class SliverTabBarDelegate extends SliverPersistentHeaderDelegate {
  final TabBar widget;
  final Color? color;
  final double? height;
  final bool? isShowBottomLine;
  const SliverTabBarDelegate({required this.widget, this.height, this.color,this.isShowBottomLine});

  @override
  Widget build(
      BuildContext context, double shrinkOffset, bool overlapsContent) {
    if(isShowBottomLine==true){
      return Container(
        color: color,
        child: Column(
          crossAxisAlignment : CrossAxisAlignment.start,
          children: [
            Container(
              color: color,
              height: height,
              child: widget,
            ),
            const Line(height: 0.5,)
          ],),);
    }
    return Container(
      color: color,
      height: height,
      child: widget,
    );
  }

  @override
  bool shouldRebuild(SliverTabBarDelegate oldDelegate) {
    return isShowBottomLine != oldDelegate.isShowBottomLine ||
        color != oldDelegate.color ||
        height != oldDelegate.height ||
        widget != oldDelegate.widget;
  }

  @override
  double get maxExtent  {
    if(isShowBottomLine==true) {
      return height! + 0.5;
    }
    return height!;
  }
//  double get maxExtent => height!;

  @override
  double get minExtent  {
    if(isShowBottomLine==true) {
      return height! + 0.5;
    }
    return height!;
  }
// double get minExtent => height!;
}

class _SliverPersistentHeaderDelegate extends SliverPersistentHeaderDelegate {
  final Widget widget;
  final double? height;

  const _SliverPersistentHeaderDelegate({required this.widget, this.height});

  @override
  Widget build(
      BuildContext context, double shrinkOffset, bool overlapsContent) {
    return Container(
      child: widget,
    );
  }

  @override
  double get maxExtent => height!;

  @override
  double get minExtent => height!;

  @override
  bool shouldRebuild(covariant _SliverPersistentHeaderDelegate oldDelegate) {
    return height != oldDelegate.height || widget != oldDelegate.widget;
  }
}


class CustomUnderlineTabIndicator extends Decoration {
  const CustomUnderlineTabIndicator({
    this.borderSide = const BorderSide(width: 2.0, color: Color(0xff2A81FF)),
    this.insets = EdgeInsets.zero,
    this.indicatorWidth = 26,
  });

  final BorderSide borderSide;

  final EdgeInsetsGeometry insets;
  ///指示器的宽度高度
  final double? indicatorWidth;

  @override
  Decoration? lerpFrom(Decoration? a, double t) {
    if (a is UnderlineTabIndicator) {
      return UnderlineTabIndicator(
        borderSide: BorderSide.lerp(a.borderSide, borderSide, t),
        insets: EdgeInsetsGeometry.lerp(a.insets, insets, t)!,
      );
    }
    return super.lerpFrom(a, t);
  }

  @override
  Decoration? lerpTo(Decoration? b, double t) {
    if (b is UnderlineTabIndicator) {
      return UnderlineTabIndicator(
        borderSide: BorderSide.lerp(borderSide, b.borderSide, t),
        insets: EdgeInsetsGeometry.lerp(insets, b.insets, t)!,
      );
    }
    return super.lerpTo(b, t);
  }

  @override
  BoxPainter createBoxPainter([ VoidCallback? onChanged ]) {
    return _UnderlinePainter(this, onChanged);
  }

  Rect _indicatorRectFor(Rect rect, TextDirection textDirection) {
    final Rect indicator = insets.resolve(textDirection).deflateRect(rect);

    //希望的宽度 默认26，为空则文字宽度，高度是borderSide.width
    double wantWidth = indicatorWidth ?? indicator.width;
    //取中间坐标
    double cw = (indicator.left + indicator.right) / 2;
    return Rect.fromLTWH(cw - wantWidth / 2,
        indicator.bottom - borderSide.width, wantWidth, borderSide.width);
  }

  @override
  Path getClipPath(Rect rect, TextDirection textDirection) {
    return Path()..addRect(_indicatorRectFor(rect, textDirection));
  }
}

class _UnderlinePainter extends BoxPainter {
  _UnderlinePainter(this.decoration, VoidCallback? onChanged)
      : super(onChanged);

  final CustomUnderlineTabIndicator decoration;

  @override
  void paint(Canvas canvas, Offset offset, ImageConfiguration configuration) {
    assert(configuration.size != null);
    final Rect rect = offset & configuration.size!;
    final TextDirection textDirection = configuration.textDirection!;
    final Rect indicator = decoration._indicatorRectFor(rect, textDirection).deflate(decoration.borderSide.width / 2.0);
    final Paint paint = decoration.borderSide.toPaint()..strokeCap = StrokeCap.round;
    canvas.drawLine(indicator.bottomLeft, indicator.bottomRight, paint);
  }
}

///横线
class Line extends StatelessWidget {
  final EdgeInsetsGeometry? margin;
  final Color? color;
  final double height;
  final double? width;

  const Line({Key? key, this.margin, this.color, this.height = 0.5, this.width})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      width: width ?? double.infinity,
      margin: margin ?? const EdgeInsets.all(0),
      height: height,
      color: color ?? const Color(0xFFE9E9E9),
    );
  }
}


